﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Xml.Linq;
using AIStudio.Wpf.DiagramDesigner;
using AIStudio.Wpf.DiagramDesigner.Algorithms;
using AIStudio.Wpf.DiagramDesigner.Geometrys;
using AIStudio.Wpf.DiagramDesigner.Helpers;
using AIStudio.Wpf.DiagramDesigner.Models;
using AIStudio.Wpf.DiagramModels;
using AIStudio.Wpf.DiagramModels.ViewModels;
using AIStudio.Wpf.Flowchart.Models;
using AIStudio.Wpf.Mind.Helpers;
using AIStudio.Wpf.Mind.Models;


namespace AIStudio.Wpf.Mind.ViewModels
{
    public class MindNode : DiagramItemViewModel
    {
        public MindNode() : this(null)
        {
        }

        public MindNode(IDiagramViewModel root) : base(root)
        {

        }

        public MindNode(IDiagramViewModel root, SelectableItemBase designer) : base(root, designer)
        {
            InitLayout(false);
        }

        public MindNode(IDiagramViewModel root, SerializableItem serializableItem, string serializableType) : base(root, serializableItem, serializableType)
        {
            InitLayout(false);
        }

        public override SelectableItemBase GetSerializableObject()
        {
            return new MindNodeDesignerItem(this);
        }

        protected override void Init(IDiagramViewModel root)
        {
            base.Init(root);

            EnabledForConnection = false;
            AlwayForResized = true;
            CustomText = true;

            AddChildCommand = (Root as IMindDiagramViewModel)?.AddChildCommand;
            AddParentCommand = (Root as IMindDiagramViewModel)?.AddParentCommand;
            AddPearCommand = (Root as IMindDiagramViewModel)?.AddPearCommand;
            DeleteCommand = (Root as IMindDiagramViewModel)?.DeleteCommand;
            MoveForwardCommand = (Root as IMindDiagramViewModel)?.MoveForwardCommand;
            MoveBackCommand = (Root as IMindDiagramViewModel)?.MoveBackCommand;
            BuildMenuOptions();
            Tags = new ObservableCollection<string>();
            LinkInfo = new LinkInfo();
            ImageInfo = new ImageInfo();
        }

        public void InitLayout(bool initAppearance)
        {
            var layout = GlobalType.AllTypes.Where(p => typeof(IMindLayout).IsAssignableFrom(p)).FirstOrDefault(p => p.Name == MindType.ToString() + "Layout");
            MindLayout = layout != null ? (System.Activator.CreateInstance(layout) as IMindLayout) : new MindLayout();

            IsInnerConnector = true;                 
            MindLayout.Appearance(this, MindThemeModel, initAppearance);
            
            this.PropertyChanged -= this.Item_PropertyChanged;
            this.PropertyChanged += this.Item_PropertyChanged;
        }

        public void ThemeChange()
        {
            MindThemeHelper.ThemeChange(this, MindThemeModel);
        }

        protected override void LoadDesignerItemViewModel(SelectableItemBase designerbase)
        {
            base.LoadDesignerItemViewModel(designerbase);

            if (designerbase is MindNodeDesignerItem designer)
            {
                Spacing = designer.Spacing;
                Offset = designer.Offset;
                IsExpanded = designer.IsExpanded;
            }
        }

        public override DiagramNode ToDiagram()
        {
            var mindNodeModel = new MindNodeModel();

            mindNodeModel.Spacing = Spacing;
            mindNodeModel.Offset = Offset;
            mindNodeModel.IsExpanded = IsExpanded;
            return mindNodeModel;
        }

        #region 属性
        public IMindLayout MindLayout
        {
            get; set;
        }

        public MindNode ParentNode
        {
            get
            {
                return Parent as MindNode;
            }

        }

        public int NodeLevel
        {
            get
            {
                if (ParentNode == null)
                {
                    return 0;
                }
                else
                {
                    return ParentNode.NodeLevel + 1;
                }
            }
        }

        public MindType MindType
        {
            get
            {
                return (Root as IMindDiagramViewModel)?.MindType ?? MindType.Mind;
            }
        }

        public MindThemeModel MindThemeModel
        {
            get
            {
                return (Root as IMindDiagramViewModel)?.MindThemeModel ?? MindThemeHelper.GetTheme("SkyBlue");
            }
        }

        private bool _isExpanded = true;
        public bool IsExpanded
        {
            get
            {
                return _isExpanded;
            }
            set
            {
                SetProperty(ref _isExpanded, value);
            }
        }

        public SizeBase Spacing
        {
            get; set;
        } = new SizeBase(15, 15);


        private ObservableCollection<MindNode> _children = new ObservableCollection<MindNode>();
        public ObservableCollection<MindNode> Children
        {
            get
            {
                return _children;
            }
            set
            {
                SetProperty(ref _children, value);
            }
        }

        public SizeBase SizeWithSpacing
        {
            get
            {
                return this.Size.Add(Spacing.Width * 2, Spacing.Height * 2);
            }
        }

        public SizeBase DesiredSize
        {
            get; set;
        }

        public PointBase DesiredPosition
        {
            get; set;
        }

        public PointBase Offset
        {
            get; set;
        }

        private ConnectorOrientation _connectorOrientation = ConnectorOrientation.Left;
        public ConnectorOrientation ConnectorOrientation
        {
            get
            {
                return _connectorOrientation;
            }
            set
            {
                SetProperty(ref _connectorOrientation, value);
            }
        }

        public bool LayoutUpdating
        {
            get; set;
        }
        #endregion

        #region 附加信息属性
        private LinkInfo _linkInfo;
        public LinkInfo LinkInfo
        {
            get
            {
                return _linkInfo;
            }
            set
            {
                if (_linkInfo != null)
                {
                    _linkInfo.PropertyChanged -= Item_PropertyChanged;
                }
                SetProperty(ref _linkInfo, value);
                if (_linkInfo != null)
                {
                    _linkInfo.PropertyChanged += Item_PropertyChanged; ;
                }
            }
        }

        private ImageInfo _imageInfo;
        public ImageInfo ImageInfo
        {
            get
            {
                return _imageInfo;
            }
            set
            {
                if (_imageInfo != null)
                {
                    _imageInfo.PropertyChanged -= Item_PropertyChanged;
                }
                SetProperty(ref _imageInfo, value);
                if (_imageInfo != null)
                {
                    _imageInfo.PropertyChanged += Item_PropertyChanged;
                }
            }
        }

        private string _remark;
        public string Remark
        {
            get
            {
                return _remark;
            }
            set
            {
                SetProperty(ref _remark, value);
            }
        }

        private double? _priority;
        public double? Priority
        {
            get
            {
                return _priority;
            }
            set
            {
                SetProperty(ref _priority, value);
            }
        }

        private double? _rate;
        public double? Rate
        {
            get
            {
                return _rate;
            }
            set
            {
                SetProperty(ref _rate, value);
            }
        }

        private ObservableCollection<string> _tags;
        public ObservableCollection<string> Tags
        {
            get
            {
                return _tags;
            }
            set
            {
                if (_tags != null)
                {
                    _tags.CollectionChanged -= _tags_CollectionChanged;
                }
                SetProperty(ref _tags, value);
                if (_tags != null)
                {
                    _tags.CollectionChanged += _tags_CollectionChanged;
                }             
            }
        }

        private void _tags_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
            {
                foreach (var item in e.NewItems.OfType<string>())
                {
                    var width = GetTextDisplayWidthHelper.GetTextDisplayWidth(item, new FontFamily(FontViewModel.FontFamily), FontViewModel.FontStyle, FontViewModel.FontWeight, FontViewModel.FontStretch, 12) + 6;
                    ItemWidth += width;
                }
            }

            if (e.OldItems != null)
            {
                foreach (var item in e.OldItems.OfType<string>())
                {
                    var width = GetTextDisplayWidthHelper.GetTextDisplayWidth(item, new FontFamily(FontViewModel.FontFamily), FontViewModel.FontStyle, FontViewModel.FontWeight, FontViewModel.FontStretch, 12) + 6;
                    ItemWidth -= width;
                }
            }
        }
        #endregion

        #region 命令
        public SimpleCommand AddParentCommand
        {
            get; private set;
        }

        public SimpleCommand AddChildCommand
        {
            get; private set;
        }

        public SimpleCommand AddPearCommand
        {
            get; private set;
        }

        public SimpleCommand DeleteCommand
        {
            get; private set;
        }

        public SimpleCommand MoveForwardCommand
        {
            get; private set;
        }

        public SimpleCommand MoveBackCommand
        {
            get; private set;
        }
        #endregion

        #region 菜单
        private void BuildMenuOptions()
        {
            menuOptions = new ObservableCollection<CinchMenuItem>();
            CinchMenuItem menuItem = new CinchMenuItem();
            menuItem.Text = "下级";
            menuItem.Command = AddChildCommand;
            menuItem.CommandParameter = this;
            menuOptions.Add(menuItem);
            menuItem = new CinchMenuItem();
            menuItem.Text = "同级";
            menuItem.Command = AddPearCommand;
            menuItem.CommandParameter = this;
            menuOptions.Add(menuItem);
            menuItem = new CinchMenuItem();
            menuItem.Text = "上级";
            menuItem.Command = AddParentCommand;
            menuItem.CommandParameter = this;
            menuOptions.Add(menuItem);
            menuItem = new CinchMenuItem();
            menuItem.Text = "前移";
            menuItem.Command = MoveForwardCommand;
            menuItem.CommandParameter = this;
            menuOptions.Add(menuItem);
            menuItem = new CinchMenuItem();
            menuItem.Text = "后移";
            menuItem.Command = MoveBackCommand;
            menuItem.CommandParameter = this;
            menuOptions.Add(menuItem);
            menuItem = new CinchMenuItem();
            menuItem.Text = "删除";
            menuItem.Command = DeleteCommand;
            menuItem.CommandParameter = this;
            menuOptions.Add(menuItem);
        }
        #endregion

        #region 操作  
        public void AddChild(MindNode item, int index = -1)
        {
            if (index >= 0)
            {
                this.Children.Insert(index, item);
            }
            else
            {
                this.Children.Add(item);
            }
            item.Parent = this;
            item.ParentId = this.Id;
            item.InitLayout(true);

            ConnectionViewModel connector = MindLayout?.GetOrSetConnectionViewModel(this, item);
            Root?.DirectAddItemCommand.Execute(new SelectableDesignerItemViewModelBase[] { item, connector });
            connector.ZIndex = -1;
            connector.IsSelected = false;
            item.IsSelected = false;
            this.IsSelected = true;
        }

        public void RemoveChild(MindNode item, bool removeall = false)
        {
            item.PropertyChanged -= Item_PropertyChanged;

            this.Children.Remove(item);

            var connectors = Root?.Items.OfType<ConnectionViewModel>().Where(p => p.SinkConnectorInfoFully?.DataItem == item).ToList();

            Root?.DirectRemoveItemCommand.Execute(item);
            Root?.DirectRemoveItemCommand.Execute(connectors);

            if (removeall)
            {
                if (item.Children?.Count > 0)
                {
                    foreach (var child in item.Children.ToList())
                    {
                        item.RemoveChild(child);
                    }
                }
            }
        }

        public void InitConnectLayout()
        {
            var connector = Root?.Items.OfType<ConnectionViewModel>().Where(p => p.IsFullConnection).FirstOrDefault(p => p.SinkConnectorInfoFully.DataItem == this);
            if (connector != null)
            {
                 MindLayout?.GetOrSetConnectionViewModel(connector.SourceConnectorInfo.DataItem as MindNode, connector.SinkConnectorInfoFully.DataItem as MindNode, connector);
            }
        }
        #endregion

        private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (GetLevel1Node()?.LayoutUpdating == true) return;

            switch (e.PropertyName)
            {
                case nameof(IsExpanded):
                case nameof(ItemWidth):
                case nameof(ItemHeight):
                    {
                        LayoutUpdated();
                        break;
                    }
                case nameof(NodeLevel):
                    MindLayout?.Appearance(this);
                    break;
                case nameof(Left):
                    {
                        if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs)
                        {
                            if (NodeLevel > 0 && IsSelected)
                            {
                                UpdateOffsetX((double)valuePropertyChangedEventArgs.OldValue, (double)valuePropertyChangedEventArgs.NewValue);
                            }
                        }
                        break;
                    }
                case nameof(Top):
                    {
                        if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs)
                        {
                            if (NodeLevel > 0 && IsSelected)
                            {
                                UpdateOffsetY((double)valuePropertyChangedEventArgs.OldValue, (double)valuePropertyChangedEventArgs.NewValue);
                            }
                        }
                        break;
                    }
                case nameof(Text):
                    {
                        ItemWidth = Math.Max(ItemWidth, GetTextDisplayWidthHelper.GetTextDisplayWidth(Text, new FontFamily(FontViewModel.FontFamily), FontViewModel.FontStyle, FontViewModel.FontWeight, FontViewModel.FontStretch, FontViewModel.FontSize) + 30);
                        break;
                    }
                case nameof(Rate):
                case nameof(Priority):               
                case nameof(Remark):
                case nameof(LinkInfo.Link):
                    {
                        if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs)
                        {
                            if (string.IsNullOrEmpty(valuePropertyChangedEventArgs.OldValue?.ToString()) && !string.IsNullOrEmpty(valuePropertyChangedEventArgs.NewValue?.ToString()))
                            {
                                ItemWidth += 24;
                            }
                            else if (!string.IsNullOrEmpty(valuePropertyChangedEventArgs.OldValue?.ToString()) && string.IsNullOrEmpty(valuePropertyChangedEventArgs.NewValue?.ToString()))
                            {
                                ItemWidth -= 24;
                            }
                        }
                        break;
                    }
                case nameof(ImageInfo.Url):
                    {
                        if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs)
                        {
                            if (string.IsNullOrEmpty(valuePropertyChangedEventArgs.OldValue?.ToString()) && !string.IsNullOrEmpty(valuePropertyChangedEventArgs.NewValue?.ToString()))
                            {
                                ItemWidth = Math.Max(ItemWidth, 160);
                                ItemHeight += 135;
                            }
                            else if (!string.IsNullOrEmpty(valuePropertyChangedEventArgs.OldValue?.ToString()) && string.IsNullOrEmpty(valuePropertyChangedEventArgs.NewValue?.ToString()))
                            {
                                ItemHeight -= 135;
                            }
                        }
                        break;
                    }
            }
        }

        public override void AddToSelection(bool selected)
        {
            foreach (SelectableDesignerItemViewModelBase item in Root.SelectedItems.ToList())
                item.IsSelected = false;

            Root.SelectedItems.Clear();
            IsSelected = selected;
        }
        #region 布局相关
        public MindNode GetLevel1Node()
        {
            var node = this;
            while (node.Parent is MindNode mindNode)
            {
                node = mindNode;
            }
            return node;
        }

        public MindNode GetLevel2Node()
        {
            var node = this;
            while (node.Parent is MindNode mindNode && mindNode.NodeLevel == 1)
            {
                node = mindNode;
            }
            return node;
        }

        protected void UpdateOffsetX(double oldvalue, double newvalue)
        {
            Offset += new VectorBase(newvalue - oldvalue, 0);
        }

        protected void UpdateOffsetY(double oldvalue, double newvalue)
        {
            Offset += new VectorBase(0, newvalue - oldvalue);
        }

        public void LayoutUpdated()
        {
            MindLayout?.LayoutUpdated(GetLevel1Node());
        }

        #endregion
    }

    public class LinkInfo : BindableBase
    {
        private string _link;
        public string Link
        {
            get
            {
                return _link;
            }
            set
            {
                SetProperty(ref _link, value);
            }
        }

        private string _text;
        public string Text
        {
            get
            {
                return _text;
            }
            set
            {
                SetProperty(ref _text, value);
            }
        }
    }

    public class ImageInfo : BindableBase
    {
        private string _url;
        public string Url
        {
            get
            {
                return _url;
            }
            set
            {
                SetProperty(ref _url, value);
            }
        }

        private string _text;
        public string Text
        {
            get
            {
                return _text;
            }
            set
            {
                SetProperty(ref _text, value);
            }
        }
    }
}
